/* video_ioctl2->__video_do_ioctl->v4l_reqbufs */

/**
 用户空间参数
 struct v4l2_buffer buf;
 struct v4l2_plane planes[FMT_NUM_PLANES];

 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 buf.memory = V4L2_MEMORY_MMAP;
 buf.index = i;
 
 if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == dev->buf_type) {
	 buf.m.planes = planes;
	 buf.length = FMT_NUM_PLANES; 
 }
 
 ioctl(dev->fd, VIDIOC_QUERYBUF, &buf)
 
 if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == dev->buf_type) {
	dev->buffers[i].length = buf.m.planes[0].length;
	dev->buffers[i].start = mmap(NULL
					  buf.m.planes[0].length,
					  PROT_READ | PROT_WRITE, MAP_SHARED
					  dev->fd, buf.m.planes[0].m.mem_offset);


 **/

static long __video_do_ioctl(struct file *file,
		unsigned int cmd, void *arg)
{
	struct video_device *vfd = video_devdata(file);
	struct mutex *lock; /* ioctl serialization mutex */
	
	/* 我们的例子中为rkisp_v4l2_ioctl_ops */
	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;

	bool write_only = false;
	struct v4l2_ioctl_info default_info;
	const struct v4l2_ioctl_info *info;
	void *fh = file->private_data;
	struct v4l2_fh *vfh = NULL;
	int dev_debug = vfd->dev_debug;
	long ret = -ENOTTY;


	if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
		vfh = file->private_data;


	if (v4l2_is_known_ioctl(cmd)) {
		/* 如果是已知ioctl */
		info = &v4l2_ioctls[_IOC_NR(cmd)];
	} else {
		/* 不是内核预定义的，既自己定义的ioctl命令 */
		default_info.ioctl = cmd;
		default_info.flags = 0;
		default_info.debug = v4l_print_default;
		info = &default_info;
	}

	write_only = _IOC_DIR(cmd) == _IOC_WRITE;
	if (info != &default_info) {
		/* 内核预定义ioctl，直接调用对应的函数, 本例中调用             v4l_querybuf */
		ret = info->func(ops, file, fh, arg);
	} else if (!ops->vidioc_default) {
		ret = -ENOTTY;
	} else {
		/* 自定义ioctl，调用 vidioc_default函数 */
		ret = ops->vidioc_default(file, fh,
			vfh ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
			cmd, arg);
	}

	return ret;
}

static int v4l_querybuf(const struct v4l2_ioctl_ops *ops,
				struct file *file, void *fh, void *arg)
{
	struct v4l2_buffer *p = arg;
	int ret = check_fmt(file, p->type);
	/* /* 调用 rkisp_v4l2_ioctl_ops->vidioc_querybuf既  vb2_ioctl_querybuf */
	return ret ? ret : ops->vidioc_querybuf(file, fh, p);
}


